# Required packages for our course. Do not delete.
library(tidyverse)
library(mosaic)
library(dplyr)
library(ggplot2)
library(plotly)
library(treemap)
library(devtools)
library(htmlwidgets)
library(d3treeR)

Introduction

The field of data science is rapidly evolving, with professionals playing pivotal roles in shaping industries across the globe. Understanding the dynamics of job roles, salaries, and related factors is crucial for both aspiring data scientists and organizations seeking to attract and retain talent. In this report, we delve into insights derived from the comprehensive dataset titled “Jobs and Salaries in Data Science,” obtained from Kaggle.

Our analysis centers around several key questions aimed at uncovering patterns and trends within the data science domain:

  1. Correlation between Employee Residence and Salary Levels: Are there discernible correlations between where data science professionals reside and the levels of their salaries? How does this correlation vary across different regions or countries?

  2. Prevalence of Job Titles Across Regions: Do certain job titles dominate specific regions or countries? By exploring this question, we aim to discern any geographical preferences or trends in job roles within the data science field.

  3. Distribution of Work Experience Levels: What is the distribution of respondents based on their years of work experience? Understanding this distribution provides valuable insights into the experience levels prevalent within the data science workforce.

  4. Trends in Work Experience Levels Across Locations: Are there notable trends in work experience levels among data science professionals residing in different locations? By analyzing this aspect, we aim to identify any geographical variations in experience levels.

  5. Trend in Salaries Across Work Years: Is there a discernible change in the average salary across different work years within the data science field?

  6. Trend in Salaries Across Experience Levels: Is there a discernible change in the average salary across different experience levels within the data science field?

Dataset Description

The “Jobs and Salaries in Data Science” dataset is a comprehensive compilation of information pertaining to salaries and related factors within the data science field. It includes details such as job title, job category, salary in various currencies, employee residence, experience level, employment type, work setting, company location, and company size. This rich dataset offers an invaluable resource for analyzing salary trends, comparing salaries across roles and regions, and understanding the factors influencing salary structures within the data industry.

In the subsequent sections of this report, we delve deeper into each research question, presenting our findings and interpretations derived from the analysis of the dataset. Through this exploration, we aim to provide actionable insights that can inform strategic decisions for both individuals and organizations operating within the dynamic landscape of data science.

Methodology

# import the dataset
jobs_in_data <- read.csv("~/Desktop/BIOINFORMATICS_MS/Semester_IV/INSH5302/Project2/jobs_in_data.csv")
# filter to include 25 random countries out of 83
set.seed(123)
selected_data <- jobs_in_data[, c("work_year", "job_title", "salary_in_usd", "experience_level", "employee_residence")]
# Extract unique countries from the "employee_residence" column
unique_countries <- unique(selected_data$employee_residence)

# Select 15 random unique countries
random_15_countries <- sample(unique_countries, 25)
filtered_data <- selected_data[selected_data$employee_residence %in% random_15_countries, ]

Analysis

Scatterplot of Salary in USD by Employee Residence

# Create the ggplot object
scatterplot <- ggplot(filtered_data, aes(x = employee_residence, y = salary_in_usd, color = employee_residence)) +
  geom_point(alpha = 0.5) + 
  labs(title = "Scatterplot of Salary in USD by Employee Residence",
       x = "Employee Residence",
       y = "Salary in USD") + scale_y_continuous(labels = scales::comma_format()) + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Convert ggplot object to a plotly object
interactive_scatterplot <- ggplotly(scatterplot)
interactive_scatterplot

The scatterplot provides a visual representation of the relationship between salary and employee residence, allowing for insights into salary distribution, regional disparities, and potential correlations. The salaries vary significantly across different employee residences, ranging from as low as $15,000 to as high as $323,905. Certain countries or regions seem to have higher salary ranges compared to others. For example, countries like France, Portugal, and Lithuania have a wide range of salary levels, including both high and moderate salaries. There are some instances of exceptionally high salaries, such as in France where the salary reaches $323,905, and in New Zealand with a salary of $125,000. Several factors could contribute to these salary differences, including local economic conditions, cost of living, demand for specific skills, and industry specialization in certain regions.

Prevalence of Job Titles Across Regions

# Create a stacked bar plot
interactive_stacked_bar <- filtered_data %>%
  group_by(employee_residence, job_title) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = employee_residence, y = count, fill = job_title)) +
  geom_bar(stat = "identity") +
  labs(title = "Prevalence of Job Titles Across Regions",
       x = "Region or Country",
       y = "Count",
       fill = "Job Title") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) 
## `summarise()` has grouped output by 'employee_residence'. You can override
## using the `.groups` argument.
# Convert the ggplot object to an interactive plot
interactive_stacked_bar <- ggplotly(interactive_stacked_bar)
interactive_stacked_bar

France: Leads with a total count of 69, encompassing a wide range of job titles including data engineering, data science, and machine learning engineering. Portugal: Follows closely with a total count of 27, with diverse roles in data analysis, data engineering, and machine learning engineering. Pakistan: Shows a smaller presence with a total count of 6, mainly in data engineering, data science consultancy, and AI programming. Philippines: Exhibits a limited presence with a total count of 4, focusing on roles such as business data analysis, data science management, and data analytics. Belgium, Lithuania, and Turkey: Each have a moderate presence with counts ranging from 2 to 4, primarily in roles like data scientist, machine learning engineer, and AI scientist. Other countries: Have minimal representation, with counts ranging from 1 to 2, encompassing specific job titles.

Distribution of Experience Levels

# Create an interactive barplot using plot_ly 
interactive_barplot <- plot_ly(data = filtered_data, x = ~experience_level, type = "histogram", marker = list(color = "brown")) %>%
  layout(title = "Distribution of Experience Levels",
         xaxis = list(title = "Experience Level"),
         yaxis = list(title = "Frequency"))

# display the interactive barplot
interactive_barplot

The distribution of experience levels among employees in the filtered dataset for 25 countries is as follows: there are 35 entry-level, 3 executive, 51 mid-level, and 43 senior-level positions. This distribution provides insight into the workforce composition and highlights the prevalence of mid-level and senior-level roles compared to entry-level and executive positions. Understanding this distribution can aid in workforce planning, talent management, and organizational development strategies.

Average Salary Over Years

# Average salary over years
average_salary <- filtered_data %>% 
  group_by(work_year) %>% 
  summarise(avg_salary = mean(salary_in_usd))

# Create an interactive line plot for average salary over years
interactive_line_plot <- plot_ly(data = average_salary, x = ~work_year, y = ~avg_salary, type = "scatter", mode = "lines+markers",
                                 line = list(color = "black")) %>%
  layout(title = "Average Salary Over Years",
         xaxis = list(title = "Year"),
         yaxis = list(title = "Average Salary (USD)"))

# display the interactive line plot
interactive_line_plot

The graph reveals a notable increase in the average salary over the years, reflecting potential trends in the job market or economic conditions. In 2020, the average salary was $59.04k, showing a slight decrese to $57.43k in 2021. However, a more significant jump occurred in 2022, with the average salary rising to $65.56k. This increase could signify factors such as industry growth, demand for skilled professionals, or inflationary pressures impacting compensation. The most substantial increase is observed in 2023, where the average salary surged to $81.09k, suggesting robust economic conditions, high demand for talent, or advancements in specialized skills driving up compensation levels. Overall, this analysis highlights the dynamic nature of salary trends and underscores the importance of monitoring and adapting to changing market conditions for both employers and employees.

Salary Distribution by Job Title

# Create interactive boxplot for salary distribution according to job title
interactive_salary_boxplot <- plot_ly(filtered_data, x = ~job_title, y = ~salary_in_usd, type = "box") %>%
  layout(title = "Salary Distribution by Job Title",
         xaxis = list(title = "Job Title"),
         yaxis = list(title = "Salary (USD)"))

# Print the interactive boxplot
interactive_salary_boxplot

The interactive boxplot analysis provides valuable insights into the salary distribution across different job titles. Among the job titles examined, “Head of Data,” “Research Engineer,” and “AI Developer” stand out for their notable variation in salary. The boxplot illustrates considerable variability in salaries within the roles, with some individuals potentially earning substantially higher or lower than the median. This variation could be attributed to factors such as years of experience, industry specialization, or additional qualifications.

Head of Data: The median salary for this position is $137,000, indicating a significant earning potential.

Research Engineer: With a median salary of $168,000, the role of a Research Engineer commands considerable compensation.

AI Developer: The median salary for AI Developers is $118,000, reflecting the demand for professionals skilled in artificial intelligence technologies.

Salary Distribution by Experience Level

# salary distribution according to experience level
# Create interactive boxplot for salary distribution according to experience level
interactive_exp_boxplot <- plot_ly(filtered_data, x = ~experience_level, y = ~salary_in_usd, type = "box") %>%
  layout(title = "Salary Distribution by Experience Level",
         xaxis = list(title = "Experience Level"),
         yaxis = list(title = "Salary (USD)"))

# Print the interactive boxplot
interactive_exp_boxplot

The salary distribution analysis by experience level reveals distinct trends:

  • Entry Level: Median salary is $40,000, typical for new or less experienced workers. This salary level reflects the compensation typically offered to individuals who are new to the workforce or have limited professional experience. Entry-level salaries may vary depending on factors such as industry, location, and specific job roles.

  • Executive: Median salary jumps to $106,000, reflecting the high responsibilities of leadership roles. Executives typically hold top leadership positions within organizations and are responsible for strategic decision-making and overseeing company operations. The higher salary range for executives reflects the significant responsibilities and leadership roles they undertake.

  • Mid Level: Median salary stands at $57,220, indicating moderate experience and responsibilities. Mid-level positions often require a moderate level of experience and expertise, with individuals assuming roles that involve greater responsibilities and specialized skills compared to entry-level positions. The salary reflects a midpoint between entry-level and senior-level compensation.

  • Senior Level: Median salary rises to $76,050, reflecting extensive experience and leadership roles. Senior-level roles typically require extensive experience, specialized skills, and a track record of leadership and accomplishments. The higher compensation reflects the value placed on the expertise and contributions of senior professionals to organizations.

Overall, salaries increase significantly as professionals progress from entry to senior levels, reflecting their experience and contributions to organizations.

Treemap of Average Salary by Employee Residence and Job Title

# Geographical salary distribution
# Group the data
grouped_data <- filtered_data %>%
  group_by(employee_residence, job_title, salary_in_usd) %>%
  summarise(count = n())
## `summarise()` has grouped output by 'employee_residence', 'job_title'. You can
## override using the `.groups` argument.
# Calculate average salary per group
average_salary <- grouped_data %>%
  group_by(job_title, employee_residence) %>%
  summarise(avg_salary = mean(salary_in_usd), .groups = 'drop')

# Create the treemap
data_science_treemap <- treemap(average_salary,
                                 index = c("job_title", "employee_residence"),
                                 vSize = "avg_salary",
                                 title = "Treemap of Average Salary by Employee Residence and Job Title")

# Print the treemap
# print(data_science_treemap)
d3tree(data_science_treemap, rootname = "Jobs")

In this analysis, we generated a treemap graph along with its interactive version, showcasing the average salary distribution according to employee residence and job titles. The treemap visualization allowed us to explore the salary trends across different countries and job roles efficiently.

Upon examination of the graph, it was evident that certain job titles commanded higher average salaries across various countries. Specifically, roles such as ML engineer, data engineer, data scientist, finance data analyst, data analyst, and head of data consistently emerged with the highest average salaries.

Salary Trend for Data Scientists Over Work Years

# salary of over years
# Filter the data for Data Scientists
data_scientist_salary <- filtered_data[filtered_data$job_title == "Data Scientist", ]

# Create the scatter plot
scatter_plot <- ggplot(data_scientist_salary, aes(x = work_year, y = salary_in_usd)) +
  geom_point(color = "blue", alpha = 0.5) +
  labs(title = "Salary Trend for Data Scientists Over Work Years",
       x = "Work Year",
       y = "Salary (USD)")

# Add trend line
scatter_plot_with_trend <- scatter_plot +
  geom_smooth(method = "lm", se = FALSE, color = "black", linewidth = 0.5)

# Convert to plotly object
interactive_plot <- ggplotly(scatter_plot_with_trend)
## `geom_smooth()` using formula = 'y ~ x'
# Print the interactive plot
interactive_plot
# TO CHECK IF THE TREND LINE IS INCREASING/DECREASING
# Fit a linear model to the data
lm_model <- lm(salary_in_usd ~ work_year, data = data_scientist_salary)

# Get the coefficients of the linear model and slop
coefficients <- coef(lm_model)
slope <- coefficients[2]

# Check if the slope is positive, indicating an increase over years
if (slope > 0) {
  cat("The trend line indicates an increase in salaries over the years.")
} else if (slope == 0) {
  cat("The trend line indicates no change in salaries over the years.")
} else {
  cat("The trend line indicates a decrease in salaries over the years.")
}
## The trend line indicates an increase in salaries over the years.

Based on our analysis focusing on the data scientist role, which appears to have the highest representation across the selected countries, we investigated the salary trends over the years. Our examination, as depicted in the graph and confirmed by the linear model results, reveals a subtle but discernible increase in salary over the years. While the upward trajectory is evident, it’s important to note that the rate of increase appears to be minimal. This observation suggests that while there is a positive trend in data scientist salaries over time, the growth rate may be relatively slow. This insight underscores the stability or modest growth in compensation for data scientists within the selected regions over the specified period.

Results

In this study, we analyzed data from 25 randomly selected countries, focusing on five key variables: job title, employee residence, salary in USD, work experience, and work year. Our analysis comprised several graphical representations, each offering insights into different aspects of the dataset:

ChatGPT Results

In this study, we analyzed data from 25 randomly selected countries, focusing on five key variables: job title, employee residence, salary in USD, work experience, and work year. Our analysis comprised several graphical representations, each offering insights into different aspects of the dataset:

  • Scatterplot Analysis: We conducted a scatterplot analysis to visualize the relationship between employee residence and salary in USD.
  • Stacked Barplot: A stacked barplot was utilized to illustrate the prevalence of various job titles across different employee residence countries.
  • Barplot of Experience Levels: We created a barplot depicting the distribution of experience levels among the sampled data.
  • Average Salary Over Years: A lineplot graph was generated to display the average salary trends over the years.
  • Salary Distribution by Job Title: We employed a boxplot to showcase the distribution of salaries according to different job titles.
  • Salary Distribution by Experience Level: Another boxplot was utilized to visualize the salary distribution across various experience levels.
  • Treemap Visualization: A treemap was constructed to present the average salary distribution by employee residence and job title.
  • Salary Trend Analysis for Data Scientists: Finally, we conducted a trend analysis specifically focusing on the salary trend for data scientists over the years.

These graphical representations offer valuable insights into the dataset, providing a comprehensive understanding of salary distributions, trends, and variations across different variables and over time.

Conclusions

In this comprehensive analysis, we delved into various aspects of salary distribution, workforce composition, and salary trends across different job titles, experience levels, and geographical regions. Through interactive visualizations and statistical analyses, we gained valuable insights into the dynamics of compensation within the industry.

The scatterplot depicting the relationship between salary and employee residence revealed significant variations in salary levels across different countries, underscoring regional disparities and potential factors influencing compensation. Furthermore, the stacked barplot provided a clear overview of the prevalence of different job titles across various employee residences, highlighting countries with a high concentration of specific roles.

Examining the distribution of experience levels among employees offered insights into the workforce composition, with a notable presence of mid-level and senior-level positions. This distribution reflects the maturity and expertise of the workforce, essential for understanding talent demographics and planning organizational strategies.

The analysis of average salary trends over the years unveiled a positive trajectory, with salaries experiencing a steady increase over time. This growth reflects broader economic conditions, industry demand, and evolving skill requirements contributing to salary escalations across different job roles and regions.

The examination of salary distributions by job title and experience level provided a nuanced understanding of compensation structures within the industry. Roles such as Head of Data, Research Engineer, and AI Developer emerged with notable salary variations, indicative of the diverse skillsets and responsibilities associated with these positions. Additionally, the analysis highlighted significant differences in salaries across experience levels, emphasizing the importance of expertise and seniority in driving compensation levels.

Finally, the treemap visualization offered a comprehensive view of average salary distributions across employee residences and job titles, highlighting lucrative roles and regions within the industry. By focusing on the data scientist role, we observed a subtle yet discernible increase in salary over the years, indicating stable or modest growth in compensation for professionals within this domain.

In conclusion, this analysis provides valuable insights for industry stakeholders, policymakers, and professionals seeking to understand salary dynamics, workforce trends, and regional variations within the field. By leveraging interactive visualizations and statistical analyses, we have shed light on key factors shaping compensation trends, offering a robust foundation for informed decision-making and strategic planning in the ever-evolving landscape of the industry.

LS0tCnRpdGxlOiAnVW5sb2NraW5nIEluc2lnaHRzOiBFeHBsb3JpbmcgU2FsYXJ5IER5bmFtaWNzIGFuZCBFbXBsb3ltZW50IFRyZW5kcyBpbiBEYXRhIFNjaWVuY2UnCmF1dGhvcjogIktyaXNobmEgUGF0ZWwiCmRhdGU6ICJGZWJydWFyeSAyNSwgMjAyNCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgZGZfcHJpbnQ6IGthYmxlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogbm8KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICAgIGFsd2F5c19hbGxvd19odG1sOiB0cnVlCi0tLQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KIyBSZXF1aXJlZCBwYWNrYWdlcyBmb3Igb3VyIGNvdXJzZS4gRG8gbm90IGRlbGV0ZS4KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobW9zYWljKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KHRyZWVtYXApCmxpYnJhcnkoZGV2dG9vbHMpCmxpYnJhcnkoaHRtbHdpZGdldHMpCmxpYnJhcnkoZDN0cmVlUikKYGBgCgoKIyBJbnRyb2R1Y3Rpb24KVGhlIGZpZWxkIG9mIGRhdGEgc2NpZW5jZSBpcyByYXBpZGx5IGV2b2x2aW5nLCB3aXRoIHByb2Zlc3Npb25hbHMgcGxheWluZyBwaXZvdGFsIHJvbGVzIGluIHNoYXBpbmcgaW5kdXN0cmllcyBhY3Jvc3MgdGhlIGdsb2JlLiBVbmRlcnN0YW5kaW5nIHRoZSBkeW5hbWljcyBvZiBqb2Igcm9sZXMsIHNhbGFyaWVzLCBhbmQgcmVsYXRlZCBmYWN0b3JzIGlzIGNydWNpYWwgZm9yIGJvdGggYXNwaXJpbmcgZGF0YSBzY2llbnRpc3RzIGFuZCBvcmdhbml6YXRpb25zIHNlZWtpbmcgdG8gYXR0cmFjdCBhbmQgcmV0YWluIHRhbGVudC4gSW4gdGhpcyByZXBvcnQsIHdlIGRlbHZlIGludG8gaW5zaWdodHMgZGVyaXZlZCBmcm9tIHRoZSBjb21wcmVoZW5zaXZlIGRhdGFzZXQgdGl0bGVkICJKb2JzIGFuZCBTYWxhcmllcyBpbiBEYXRhIFNjaWVuY2UsIiBvYnRhaW5lZCBmcm9tIEthZ2dsZS4KCk91ciBhbmFseXNpcyBjZW50ZXJzIGFyb3VuZCBzZXZlcmFsIGtleSBxdWVzdGlvbnMgYWltZWQgYXQgdW5jb3ZlcmluZyBwYXR0ZXJucyBhbmQgdHJlbmRzIHdpdGhpbiB0aGUgZGF0YSBzY2llbmNlIGRvbWFpbjoKCjEuICoqQ29ycmVsYXRpb24gYmV0d2VlbiBFbXBsb3llZSBSZXNpZGVuY2UgYW5kIFNhbGFyeSBMZXZlbHM6KiogQXJlIHRoZXJlIGRpc2Nlcm5pYmxlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHdoZXJlIGRhdGEgc2NpZW5jZSBwcm9mZXNzaW9uYWxzIHJlc2lkZSBhbmQgdGhlIGxldmVscyBvZiB0aGVpciBzYWxhcmllcz8gSG93IGRvZXMgdGhpcyBjb3JyZWxhdGlvbiB2YXJ5IGFjcm9zcyBkaWZmZXJlbnQgcmVnaW9ucyBvciBjb3VudHJpZXM/CgoyLiAqKlByZXZhbGVuY2Ugb2YgSm9iIFRpdGxlcyBBY3Jvc3MgUmVnaW9uczoqKiBEbyBjZXJ0YWluIGpvYiB0aXRsZXMgZG9taW5hdGUgc3BlY2lmaWMgcmVnaW9ucyBvciBjb3VudHJpZXM/IEJ5IGV4cGxvcmluZyB0aGlzIHF1ZXN0aW9uLCB3ZSBhaW0gdG8gZGlzY2VybiBhbnkgZ2VvZ3JhcGhpY2FsIHByZWZlcmVuY2VzIG9yIHRyZW5kcyBpbiBqb2Igcm9sZXMgd2l0aGluIHRoZSBkYXRhIHNjaWVuY2UgZmllbGQuCgozLiAqKkRpc3RyaWJ1dGlvbiBvZiBXb3JrIEV4cGVyaWVuY2UgTGV2ZWxzOioqIFdoYXQgaXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiByZXNwb25kZW50cyBiYXNlZCBvbiB0aGVpciB5ZWFycyBvZiB3b3JrIGV4cGVyaWVuY2U/IFVuZGVyc3RhbmRpbmcgdGhpcyBkaXN0cmlidXRpb24gcHJvdmlkZXMgdmFsdWFibGUgaW5zaWdodHMgaW50byB0aGUgZXhwZXJpZW5jZSBsZXZlbHMgcHJldmFsZW50IHdpdGhpbiB0aGUgZGF0YSBzY2llbmNlIHdvcmtmb3JjZS4KCjQuICoqVHJlbmRzIGluIFdvcmsgRXhwZXJpZW5jZSBMZXZlbHMgQWNyb3NzIExvY2F0aW9uczoqKiBBcmUgdGhlcmUgbm90YWJsZSB0cmVuZHMgaW4gd29yayBleHBlcmllbmNlIGxldmVscyBhbW9uZyBkYXRhIHNjaWVuY2UgcHJvZmVzc2lvbmFscyByZXNpZGluZyBpbiBkaWZmZXJlbnQgbG9jYXRpb25zPyBCeSBhbmFseXppbmcgdGhpcyBhc3BlY3QsIHdlIGFpbSB0byBpZGVudGlmeSBhbnkgZ2VvZ3JhcGhpY2FsIHZhcmlhdGlvbnMgaW4gZXhwZXJpZW5jZSBsZXZlbHMuCgo1LiAqKlRyZW5kIGluIFNhbGFyaWVzIEFjcm9zcyBXb3JrIFllYXJzOioqIElzIHRoZXJlIGEgZGlzY2VybmlibGUgY2hhbmdlIGluIHRoZSBhdmVyYWdlIHNhbGFyeSBhY3Jvc3MgZGlmZmVyZW50IHdvcmsgeWVhcnMgd2l0aGluIHRoZSBkYXRhIHNjaWVuY2UgZmllbGQ/Cgo2LiAqKlRyZW5kIGluIFNhbGFyaWVzIEFjcm9zcyBFeHBlcmllbmNlIExldmVsczoqKiBJcyB0aGVyZSBhIGRpc2Nlcm5pYmxlIGNoYW5nZSBpbiB0aGUgYXZlcmFnZSBzYWxhcnkgYWNyb3NzIGRpZmZlcmVudCBleHBlcmllbmNlIGxldmVscyB3aXRoaW4gdGhlIGRhdGEgc2NpZW5jZSBmaWVsZD8KCiMjIyBEYXRhc2V0IERlc2NyaXB0aW9uCgpUaGUgIkpvYnMgYW5kIFNhbGFyaWVzIGluIERhdGEgU2NpZW5jZSIgZGF0YXNldCBpcyBhIGNvbXByZWhlbnNpdmUgY29tcGlsYXRpb24gb2YgaW5mb3JtYXRpb24gcGVydGFpbmluZyB0byBzYWxhcmllcyBhbmQgcmVsYXRlZCBmYWN0b3JzIHdpdGhpbiB0aGUgZGF0YSBzY2llbmNlIGZpZWxkLiBJdCBpbmNsdWRlcyBkZXRhaWxzIHN1Y2ggYXMgam9iIHRpdGxlLCBqb2IgY2F0ZWdvcnksIHNhbGFyeSBpbiB2YXJpb3VzIGN1cnJlbmNpZXMsIGVtcGxveWVlIHJlc2lkZW5jZSwgZXhwZXJpZW5jZSBsZXZlbCwgZW1wbG95bWVudCB0eXBlLCB3b3JrIHNldHRpbmcsIGNvbXBhbnkgbG9jYXRpb24sIGFuZCBjb21wYW55IHNpemUuIFRoaXMgcmljaCBkYXRhc2V0IG9mZmVycyBhbiBpbnZhbHVhYmxlIHJlc291cmNlIGZvciBhbmFseXppbmcgc2FsYXJ5IHRyZW5kcywgY29tcGFyaW5nIHNhbGFyaWVzIGFjcm9zcyByb2xlcyBhbmQgcmVnaW9ucywgYW5kIHVuZGVyc3RhbmRpbmcgdGhlIGZhY3RvcnMgaW5mbHVlbmNpbmcgc2FsYXJ5IHN0cnVjdHVyZXMgd2l0aGluIHRoZSBkYXRhIGluZHVzdHJ5LgoKSW4gdGhlIHN1YnNlcXVlbnQgc2VjdGlvbnMgb2YgdGhpcyByZXBvcnQsIHdlIGRlbHZlIGRlZXBlciBpbnRvIGVhY2ggcmVzZWFyY2ggcXVlc3Rpb24sIHByZXNlbnRpbmcgb3VyIGZpbmRpbmdzIGFuZCBpbnRlcnByZXRhdGlvbnMgZGVyaXZlZCBmcm9tIHRoZSBhbmFseXNpcyBvZiB0aGUgZGF0YXNldC4gVGhyb3VnaCB0aGlzIGV4cGxvcmF0aW9uLCB3ZSBhaW0gdG8gcHJvdmlkZSBhY3Rpb25hYmxlIGluc2lnaHRzIHRoYXQgY2FuIGluZm9ybSBzdHJhdGVnaWMgZGVjaXNpb25zIGZvciBib3RoIGluZGl2aWR1YWxzIGFuZCBvcmdhbml6YXRpb25zIG9wZXJhdGluZyB3aXRoaW4gdGhlIGR5bmFtaWMgbGFuZHNjYXBlIG9mIGRhdGEgc2NpZW5jZS4KCiMgTWV0aG9kb2xvZ3kKCmBgYHtyfQojIGltcG9ydCB0aGUgZGF0YXNldApqb2JzX2luX2RhdGEgPC0gcmVhZC5jc3YoIn4vRGVza3RvcC9CSU9JTkZPUk1BVElDU19NUy9TZW1lc3Rlcl9JVi9JTlNINTMwMi9Qcm9qZWN0Mi9qb2JzX2luX2RhdGEuY3N2IikKIyBmaWx0ZXIgdG8gaW5jbHVkZSAyNSByYW5kb20gY291bnRyaWVzIG91dCBvZiA4MwpzZXQuc2VlZCgxMjMpCnNlbGVjdGVkX2RhdGEgPC0gam9ic19pbl9kYXRhWywgYygid29ya195ZWFyIiwgImpvYl90aXRsZSIsICJzYWxhcnlfaW5fdXNkIiwgImV4cGVyaWVuY2VfbGV2ZWwiLCAiZW1wbG95ZWVfcmVzaWRlbmNlIildCiMgRXh0cmFjdCB1bmlxdWUgY291bnRyaWVzIGZyb20gdGhlICJlbXBsb3llZV9yZXNpZGVuY2UiIGNvbHVtbgp1bmlxdWVfY291bnRyaWVzIDwtIHVuaXF1ZShzZWxlY3RlZF9kYXRhJGVtcGxveWVlX3Jlc2lkZW5jZSkKCiMgU2VsZWN0IDE1IHJhbmRvbSB1bmlxdWUgY291bnRyaWVzCnJhbmRvbV8xNV9jb3VudHJpZXMgPC0gc2FtcGxlKHVuaXF1ZV9jb3VudHJpZXMsIDI1KQpmaWx0ZXJlZF9kYXRhIDwtIHNlbGVjdGVkX2RhdGFbc2VsZWN0ZWRfZGF0YSRlbXBsb3llZV9yZXNpZGVuY2UgJWluJSByYW5kb21fMTVfY291bnRyaWVzLCBdCmBgYAoKIyBBbmFseXNpcwoKIyMgU2NhdHRlcnBsb3Qgb2YgU2FsYXJ5IGluIFVTRCBieSBFbXBsb3llZSBSZXNpZGVuY2UKCmBgYHtyfQojIENyZWF0ZSB0aGUgZ2dwbG90IG9iamVjdApzY2F0dGVycGxvdCA8LSBnZ3Bsb3QoZmlsdGVyZWRfZGF0YSwgYWVzKHggPSBlbXBsb3llZV9yZXNpZGVuY2UsIHkgPSBzYWxhcnlfaW5fdXNkLCBjb2xvciA9IGVtcGxveWVlX3Jlc2lkZW5jZSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArIAogIGxhYnModGl0bGUgPSAiU2NhdHRlcnBsb3Qgb2YgU2FsYXJ5IGluIFVTRCBieSBFbXBsb3llZSBSZXNpZGVuY2UiLAogICAgICAgeCA9ICJFbXBsb3llZSBSZXNpZGVuY2UiLAogICAgICAgeSA9ICJTYWxhcnkgaW4gVVNEIikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYV9mb3JtYXQoKSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCiMgQ29udmVydCBnZ3Bsb3Qgb2JqZWN0IHRvIGEgcGxvdGx5IG9iamVjdAppbnRlcmFjdGl2ZV9zY2F0dGVycGxvdCA8LSBnZ3Bsb3RseShzY2F0dGVycGxvdCkKaW50ZXJhY3RpdmVfc2NhdHRlcnBsb3QKCmBgYAoKVGhlIHNjYXR0ZXJwbG90IHByb3ZpZGVzIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBzYWxhcnkgYW5kIGVtcGxveWVlIHJlc2lkZW5jZSwgYWxsb3dpbmcgZm9yIGluc2lnaHRzIGludG8gc2FsYXJ5IGRpc3RyaWJ1dGlvbiwgcmVnaW9uYWwgZGlzcGFyaXRpZXMsIGFuZCBwb3RlbnRpYWwgY29ycmVsYXRpb25zLiBUaGUgc2FsYXJpZXMgdmFyeSBzaWduaWZpY2FudGx5IGFjcm9zcyBkaWZmZXJlbnQgZW1wbG95ZWUgcmVzaWRlbmNlcywgcmFuZ2luZyBmcm9tIGFzIGxvdyBhcyAkMTUsMDAwIHRvIGFzIGhpZ2ggYXMgJDMyMyw5MDUuIENlcnRhaW4gY291bnRyaWVzIG9yIHJlZ2lvbnMgc2VlbSB0byBoYXZlIGhpZ2hlciBzYWxhcnkgcmFuZ2VzIGNvbXBhcmVkIHRvIG90aGVycy4gRm9yIGV4YW1wbGUsIGNvdW50cmllcyBsaWtlIEZyYW5jZSwgUG9ydHVnYWwsIGFuZCBMaXRodWFuaWEgaGF2ZSBhIHdpZGUgcmFuZ2Ugb2Ygc2FsYXJ5IGxldmVscywgaW5jbHVkaW5nIGJvdGggaGlnaCBhbmQgbW9kZXJhdGUgc2FsYXJpZXMuIFRoZXJlIGFyZSBzb21lIGluc3RhbmNlcyBvZiBleGNlcHRpb25hbGx5IGhpZ2ggc2FsYXJpZXMsIHN1Y2ggYXMgaW4gRnJhbmNlIHdoZXJlIHRoZSBzYWxhcnkgcmVhY2hlcyAkMzIzLDkwNSwgYW5kIGluIE5ldyBaZWFsYW5kIHdpdGggYSBzYWxhcnkgb2YgJDEyNSwwMDAuIFNldmVyYWwgZmFjdG9ycyBjb3VsZCBjb250cmlidXRlIHRvIHRoZXNlIHNhbGFyeSBkaWZmZXJlbmNlcywgaW5jbHVkaW5nIGxvY2FsIGVjb25vbWljIGNvbmRpdGlvbnMsIGNvc3Qgb2YgbGl2aW5nLCBkZW1hbmQgZm9yIHNwZWNpZmljIHNraWxscywgYW5kIGluZHVzdHJ5IHNwZWNpYWxpemF0aW9uIGluIGNlcnRhaW4gcmVnaW9ucy4KCgojIyBQcmV2YWxlbmNlIG9mIEpvYiBUaXRsZXMgQWNyb3NzIFJlZ2lvbnMKCmBgYHtyfQojIENyZWF0ZSBhIHN0YWNrZWQgYmFyIHBsb3QKaW50ZXJhY3RpdmVfc3RhY2tlZF9iYXIgPC0gZmlsdGVyZWRfZGF0YSAlPiUKICBncm91cF9ieShlbXBsb3llZV9yZXNpZGVuY2UsIGpvYl90aXRsZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBlbXBsb3llZV9yZXNpZGVuY2UsIHkgPSBjb3VudCwgZmlsbCA9IGpvYl90aXRsZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnModGl0bGUgPSAiUHJldmFsZW5jZSBvZiBKb2IgVGl0bGVzIEFjcm9zcyBSZWdpb25zIiwKICAgICAgIHggPSAiUmVnaW9uIG9yIENvdW50cnkiLAogICAgICAgeSA9ICJDb3VudCIsCiAgICAgICBmaWxsID0gIkpvYiBUaXRsZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpIAoKIyBDb252ZXJ0IHRoZSBnZ3Bsb3Qgb2JqZWN0IHRvIGFuIGludGVyYWN0aXZlIHBsb3QKaW50ZXJhY3RpdmVfc3RhY2tlZF9iYXIgPC0gZ2dwbG90bHkoaW50ZXJhY3RpdmVfc3RhY2tlZF9iYXIpCmludGVyYWN0aXZlX3N0YWNrZWRfYmFyCgpgYGAKCmBGcmFuY2VgOiBMZWFkcyB3aXRoIGEgdG90YWwgY291bnQgb2YgNjksIGVuY29tcGFzc2luZyBhIHdpZGUgcmFuZ2Ugb2Ygam9iIHRpdGxlcyBpbmNsdWRpbmcgZGF0YSBlbmdpbmVlcmluZywgZGF0YSBzY2llbmNlLCBhbmQgbWFjaGluZSBsZWFybmluZyBlbmdpbmVlcmluZy4KYFBvcnR1Z2FsYDogRm9sbG93cyBjbG9zZWx5IHdpdGggYSB0b3RhbCBjb3VudCBvZiAyNywgd2l0aCBkaXZlcnNlIHJvbGVzIGluIGRhdGEgYW5hbHlzaXMsIGRhdGEgZW5naW5lZXJpbmcsIGFuZCBtYWNoaW5lIGxlYXJuaW5nIGVuZ2luZWVyaW5nLgpgUGFraXN0YW5gOiBTaG93cyBhIHNtYWxsZXIgcHJlc2VuY2Ugd2l0aCBhIHRvdGFsIGNvdW50IG9mIDYsIG1haW5seSBpbiBkYXRhIGVuZ2luZWVyaW5nLCBkYXRhIHNjaWVuY2UgY29uc3VsdGFuY3ksIGFuZCBBSSBwcm9ncmFtbWluZy4KYFBoaWxpcHBpbmVzYDogRXhoaWJpdHMgYSBsaW1pdGVkIHByZXNlbmNlIHdpdGggYSB0b3RhbCBjb3VudCBvZiA0LCBmb2N1c2luZyBvbiByb2xlcyBzdWNoIGFzIGJ1c2luZXNzIGRhdGEgYW5hbHlzaXMsIGRhdGEgc2NpZW5jZSBtYW5hZ2VtZW50LCBhbmQgZGF0YSBhbmFseXRpY3MuCmBCZWxnaXVtLCBMaXRodWFuaWEsIGFuZCBUdXJrZXlgOiBFYWNoIGhhdmUgYSBtb2RlcmF0ZSBwcmVzZW5jZSB3aXRoIGNvdW50cyByYW5naW5nIGZyb20gMiB0byA0LCBwcmltYXJpbHkgaW4gcm9sZXMgbGlrZSBkYXRhIHNjaWVudGlzdCwgbWFjaGluZSBsZWFybmluZyBlbmdpbmVlciwgYW5kIEFJIHNjaWVudGlzdC4KYE90aGVyIGNvdW50cmllc2A6IEhhdmUgbWluaW1hbCByZXByZXNlbnRhdGlvbiwgd2l0aCBjb3VudHMgcmFuZ2luZyBmcm9tIDEgdG8gMiwgZW5jb21wYXNzaW5nIHNwZWNpZmljIGpvYiB0aXRsZXMuCgojIyBEaXN0cmlidXRpb24gb2YgRXhwZXJpZW5jZSBMZXZlbHMKCmBgYHtyfQojIENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBiYXJwbG90IHVzaW5nIHBsb3RfbHkgCmludGVyYWN0aXZlX2JhcnBsb3QgPC0gcGxvdF9seShkYXRhID0gZmlsdGVyZWRfZGF0YSwgeCA9IH5leHBlcmllbmNlX2xldmVsLCB0eXBlID0gImhpc3RvZ3JhbSIsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAiYnJvd24iKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBFeHBlcmllbmNlIExldmVscyIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJFeHBlcmllbmNlIExldmVsIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJGcmVxdWVuY3kiKSkKCiMgZGlzcGxheSB0aGUgaW50ZXJhY3RpdmUgYmFycGxvdAppbnRlcmFjdGl2ZV9iYXJwbG90CgpgYGAKClRoZSBkaXN0cmlidXRpb24gb2YgZXhwZXJpZW5jZSBsZXZlbHMgYW1vbmcgZW1wbG95ZWVzIGluIHRoZSBmaWx0ZXJlZCBkYXRhc2V0IGZvciAyNSBjb3VudHJpZXMgaXMgYXMgZm9sbG93czogdGhlcmUgYXJlIDM1IGVudHJ5LWxldmVsLCAzIGV4ZWN1dGl2ZSwgNTEgbWlkLWxldmVsLCBhbmQgNDMgc2VuaW9yLWxldmVsIHBvc2l0aW9ucy4gVGhpcyBkaXN0cmlidXRpb24gcHJvdmlkZXMgaW5zaWdodCBpbnRvIHRoZSB3b3JrZm9yY2UgY29tcG9zaXRpb24gYW5kIGhpZ2hsaWdodHMgdGhlIHByZXZhbGVuY2Ugb2YgbWlkLWxldmVsIGFuZCBzZW5pb3ItbGV2ZWwgcm9sZXMgY29tcGFyZWQgdG8gZW50cnktbGV2ZWwgYW5kIGV4ZWN1dGl2ZSBwb3NpdGlvbnMuIFVuZGVyc3RhbmRpbmcgdGhpcyBkaXN0cmlidXRpb24gY2FuIGFpZCBpbiB3b3JrZm9yY2UgcGxhbm5pbmcsIHRhbGVudCBtYW5hZ2VtZW50LCBhbmQgb3JnYW5pemF0aW9uYWwgZGV2ZWxvcG1lbnQgc3RyYXRlZ2llcy4KCiMjIEF2ZXJhZ2UgU2FsYXJ5IE92ZXIgWWVhcnMKCmBgYHtyfQojIEF2ZXJhZ2Ugc2FsYXJ5IG92ZXIgeWVhcnMKYXZlcmFnZV9zYWxhcnkgPC0gZmlsdGVyZWRfZGF0YSAlPiUgCiAgZ3JvdXBfYnkod29ya195ZWFyKSAlPiUgCiAgc3VtbWFyaXNlKGF2Z19zYWxhcnkgPSBtZWFuKHNhbGFyeV9pbl91c2QpKQoKIyBDcmVhdGUgYW4gaW50ZXJhY3RpdmUgbGluZSBwbG90IGZvciBhdmVyYWdlIHNhbGFyeSBvdmVyIHllYXJzCmludGVyYWN0aXZlX2xpbmVfcGxvdCA8LSBwbG90X2x5KGRhdGEgPSBhdmVyYWdlX3NhbGFyeSwgeCA9IH53b3JrX3llYXIsIHkgPSB+YXZnX3NhbGFyeSwgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJsaW5lcyttYXJrZXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siKSkgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkF2ZXJhZ2UgU2FsYXJ5IE92ZXIgWWVhcnMiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiWWVhciIpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQXZlcmFnZSBTYWxhcnkgKFVTRCkiKSkKCiMgZGlzcGxheSB0aGUgaW50ZXJhY3RpdmUgbGluZSBwbG90CmludGVyYWN0aXZlX2xpbmVfcGxvdAoKYGBgClRoZSBncmFwaCByZXZlYWxzIGEgbm90YWJsZSBpbmNyZWFzZSBpbiB0aGUgYXZlcmFnZSBzYWxhcnkgb3ZlciB0aGUgeWVhcnMsIHJlZmxlY3RpbmcgcG90ZW50aWFsIHRyZW5kcyBpbiB0aGUgam9iIG1hcmtldCBvciBlY29ub21pYyBjb25kaXRpb25zLiBJbiAyMDIwLCB0aGUgYXZlcmFnZSBzYWxhcnkgd2FzICQ1OS4wNGssIHNob3dpbmcgYSBzbGlnaHQgZGVjcmVzZSB0byAkNTcuNDNrIGluIDIwMjEuIEhvd2V2ZXIsIGEgbW9yZSBzaWduaWZpY2FudCBqdW1wIG9jY3VycmVkIGluIDIwMjIsIHdpdGggdGhlIGF2ZXJhZ2Ugc2FsYXJ5IHJpc2luZyB0byAkNjUuNTZrLiBUaGlzIGluY3JlYXNlIGNvdWxkIHNpZ25pZnkgZmFjdG9ycyBzdWNoIGFzIGluZHVzdHJ5IGdyb3d0aCwgZGVtYW5kIGZvciBza2lsbGVkIHByb2Zlc3Npb25hbHMsIG9yIGluZmxhdGlvbmFyeSBwcmVzc3VyZXMgaW1wYWN0aW5nIGNvbXBlbnNhdGlvbi4gVGhlIG1vc3Qgc3Vic3RhbnRpYWwgaW5jcmVhc2UgaXMgb2JzZXJ2ZWQgaW4gMjAyMywgd2hlcmUgdGhlIGF2ZXJhZ2Ugc2FsYXJ5IHN1cmdlZCB0byAkODEuMDlrLCBzdWdnZXN0aW5nIHJvYnVzdCBlY29ub21pYyBjb25kaXRpb25zLCBoaWdoIGRlbWFuZCBmb3IgdGFsZW50LCBvciBhZHZhbmNlbWVudHMgaW4gc3BlY2lhbGl6ZWQgc2tpbGxzIGRyaXZpbmcgdXAgY29tcGVuc2F0aW9uIGxldmVscy4gT3ZlcmFsbCwgdGhpcyBhbmFseXNpcyBoaWdobGlnaHRzIHRoZSBkeW5hbWljIG5hdHVyZSBvZiBzYWxhcnkgdHJlbmRzIGFuZCB1bmRlcnNjb3JlcyB0aGUgaW1wb3J0YW5jZSBvZiBtb25pdG9yaW5nIGFuZCBhZGFwdGluZyB0byBjaGFuZ2luZyBtYXJrZXQgY29uZGl0aW9ucyBmb3IgYm90aCBlbXBsb3llcnMgYW5kIGVtcGxveWVlcy4KCiMjIFNhbGFyeSBEaXN0cmlidXRpb24gYnkgSm9iIFRpdGxlCgpgYGB7cn0KIyBDcmVhdGUgaW50ZXJhY3RpdmUgYm94cGxvdCBmb3Igc2FsYXJ5IGRpc3RyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gam9iIHRpdGxlCmludGVyYWN0aXZlX3NhbGFyeV9ib3hwbG90IDwtIHBsb3RfbHkoZmlsdGVyZWRfZGF0YSwgeCA9IH5qb2JfdGl0bGUsIHkgPSB+c2FsYXJ5X2luX3VzZCwgdHlwZSA9ICJib3giKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiU2FsYXJ5IERpc3RyaWJ1dGlvbiBieSBKb2IgVGl0bGUiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiSm9iIFRpdGxlIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJTYWxhcnkgKFVTRCkiKSkKCiMgUHJpbnQgdGhlIGludGVyYWN0aXZlIGJveHBsb3QKaW50ZXJhY3RpdmVfc2FsYXJ5X2JveHBsb3QKYGBgCgpUaGUgaW50ZXJhY3RpdmUgYm94cGxvdCBhbmFseXNpcyBwcm92aWRlcyB2YWx1YWJsZSBpbnNpZ2h0cyBpbnRvIHRoZSBzYWxhcnkgZGlzdHJpYnV0aW9uIGFjcm9zcyBkaWZmZXJlbnQgam9iIHRpdGxlcy4gQW1vbmcgdGhlIGpvYiB0aXRsZXMgZXhhbWluZWQsICJIZWFkIG9mIERhdGEsIiAiUmVzZWFyY2ggRW5naW5lZXIsIiBhbmQgIkFJIERldmVsb3BlciIgc3RhbmQgb3V0IGZvciB0aGVpciBub3RhYmxlIHZhcmlhdGlvbiBpbiBzYWxhcnkuIFRoZSBib3hwbG90IGlsbHVzdHJhdGVzIGNvbnNpZGVyYWJsZSB2YXJpYWJpbGl0eSBpbiBzYWxhcmllcyB3aXRoaW4gdGhlIHJvbGVzLCB3aXRoIHNvbWUgaW5kaXZpZHVhbHMgcG90ZW50aWFsbHkgZWFybmluZyBzdWJzdGFudGlhbGx5IGhpZ2hlciBvciBsb3dlciB0aGFuIHRoZSBtZWRpYW4uIFRoaXMgdmFyaWF0aW9uIGNvdWxkIGJlIGF0dHJpYnV0ZWQgdG8gZmFjdG9ycyBzdWNoIGFzIHllYXJzIG9mIGV4cGVyaWVuY2UsIGluZHVzdHJ5IHNwZWNpYWxpemF0aW9uLCBvciBhZGRpdGlvbmFsIHF1YWxpZmljYXRpb25zLgoKSGVhZCBvZiBEYXRhOiBUaGUgbWVkaWFuIHNhbGFyeSBmb3IgdGhpcyBwb3NpdGlvbiBpcyAkMTM3LDAwMCwgaW5kaWNhdGluZyBhIHNpZ25pZmljYW50IGVhcm5pbmcgcG90ZW50aWFsLiAKClJlc2VhcmNoIEVuZ2luZWVyOiBXaXRoIGEgbWVkaWFuIHNhbGFyeSBvZiAkMTY4LDAwMCwgdGhlIHJvbGUgb2YgYSBSZXNlYXJjaCBFbmdpbmVlciBjb21tYW5kcyBjb25zaWRlcmFibGUgY29tcGVuc2F0aW9uLiAKCkFJIERldmVsb3BlcjogVGhlIG1lZGlhbiBzYWxhcnkgZm9yIEFJIERldmVsb3BlcnMgaXMgJDExOCwwMDAsIHJlZmxlY3RpbmcgdGhlIGRlbWFuZCBmb3IgcHJvZmVzc2lvbmFscyBza2lsbGVkIGluIGFydGlmaWNpYWwgaW50ZWxsaWdlbmNlIHRlY2hub2xvZ2llcy4KCiMjIFNhbGFyeSBEaXN0cmlidXRpb24gYnkgRXhwZXJpZW5jZSBMZXZlbAoKYGBge3J9CiMgc2FsYXJ5IGRpc3RyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gZXhwZXJpZW5jZSBsZXZlbAojIENyZWF0ZSBpbnRlcmFjdGl2ZSBib3hwbG90IGZvciBzYWxhcnkgZGlzdHJpYnV0aW9uIGFjY29yZGluZyB0byBleHBlcmllbmNlIGxldmVsCmludGVyYWN0aXZlX2V4cF9ib3hwbG90IDwtIHBsb3RfbHkoZmlsdGVyZWRfZGF0YSwgeCA9IH5leHBlcmllbmNlX2xldmVsLCB5ID0gfnNhbGFyeV9pbl91c2QsIHR5cGUgPSAiYm94IikgJT4lCiAgbGF5b3V0KHRpdGxlID0gIlNhbGFyeSBEaXN0cmlidXRpb24gYnkgRXhwZXJpZW5jZSBMZXZlbCIsCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJFeHBlcmllbmNlIExldmVsIiksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJTYWxhcnkgKFVTRCkiKSkKCiMgUHJpbnQgdGhlIGludGVyYWN0aXZlIGJveHBsb3QKaW50ZXJhY3RpdmVfZXhwX2JveHBsb3QKYGBgCgpUaGUgc2FsYXJ5IGRpc3RyaWJ1dGlvbiBhbmFseXNpcyBieSBleHBlcmllbmNlIGxldmVsIHJldmVhbHMgZGlzdGluY3QgdHJlbmRzOgoKLSBFbnRyeSBMZXZlbDogTWVkaWFuIHNhbGFyeSBpcyAkNDAsMDAwLCB0eXBpY2FsIGZvciBuZXcgb3IgbGVzcyBleHBlcmllbmNlZCB3b3JrZXJzLiAgVGhpcyBzYWxhcnkgbGV2ZWwgcmVmbGVjdHMgdGhlIGNvbXBlbnNhdGlvbiB0eXBpY2FsbHkgb2ZmZXJlZCB0byBpbmRpdmlkdWFscyB3aG8gYXJlIG5ldyB0byB0aGUgd29ya2ZvcmNlIG9yIGhhdmUgbGltaXRlZCBwcm9mZXNzaW9uYWwgZXhwZXJpZW5jZS4gRW50cnktbGV2ZWwgc2FsYXJpZXMgbWF5IHZhcnkgZGVwZW5kaW5nIG9uIGZhY3RvcnMgc3VjaCBhcyBpbmR1c3RyeSwgbG9jYXRpb24sIGFuZCBzcGVjaWZpYyBqb2Igcm9sZXMuCgotIEV4ZWN1dGl2ZTogTWVkaWFuIHNhbGFyeSBqdW1wcyB0byAkMTA2LDAwMCwgcmVmbGVjdGluZyB0aGUgaGlnaCByZXNwb25zaWJpbGl0aWVzIG9mIGxlYWRlcnNoaXAgcm9sZXMuIEV4ZWN1dGl2ZXMgdHlwaWNhbGx5IGhvbGQgdG9wIGxlYWRlcnNoaXAgcG9zaXRpb25zIHdpdGhpbiBvcmdhbml6YXRpb25zIGFuZCBhcmUgcmVzcG9uc2libGUgZm9yIHN0cmF0ZWdpYyBkZWNpc2lvbi1tYWtpbmcgYW5kIG92ZXJzZWVpbmcgY29tcGFueSBvcGVyYXRpb25zLiBUaGUgaGlnaGVyIHNhbGFyeSByYW5nZSBmb3IgZXhlY3V0aXZlcyByZWZsZWN0cyB0aGUgc2lnbmlmaWNhbnQgcmVzcG9uc2liaWxpdGllcyBhbmQgbGVhZGVyc2hpcCByb2xlcyB0aGV5IHVuZGVydGFrZS4KCi0gTWlkIExldmVsOiBNZWRpYW4gc2FsYXJ5IHN0YW5kcyBhdCAkNTcsMjIwLCBpbmRpY2F0aW5nIG1vZGVyYXRlIGV4cGVyaWVuY2UgYW5kIHJlc3BvbnNpYmlsaXRpZXMuIE1pZC1sZXZlbCBwb3NpdGlvbnMgb2Z0ZW4gcmVxdWlyZSBhIG1vZGVyYXRlIGxldmVsIG9mIGV4cGVyaWVuY2UgYW5kIGV4cGVydGlzZSwgd2l0aCBpbmRpdmlkdWFscyBhc3N1bWluZyByb2xlcyB0aGF0IGludm9sdmUgZ3JlYXRlciByZXNwb25zaWJpbGl0aWVzIGFuZCBzcGVjaWFsaXplZCBza2lsbHMgY29tcGFyZWQgdG8gZW50cnktbGV2ZWwgcG9zaXRpb25zLiBUaGUgc2FsYXJ5IHJlZmxlY3RzIGEgbWlkcG9pbnQgYmV0d2VlbiBlbnRyeS1sZXZlbCBhbmQgc2VuaW9yLWxldmVsIGNvbXBlbnNhdGlvbi4KCi0gU2VuaW9yIExldmVsOiBNZWRpYW4gc2FsYXJ5IHJpc2VzIHRvICQ3NiwwNTAsIHJlZmxlY3RpbmcgZXh0ZW5zaXZlIGV4cGVyaWVuY2UgYW5kIGxlYWRlcnNoaXAgcm9sZXMuIFNlbmlvci1sZXZlbCByb2xlcyB0eXBpY2FsbHkgcmVxdWlyZSBleHRlbnNpdmUgZXhwZXJpZW5jZSwgc3BlY2lhbGl6ZWQgc2tpbGxzLCBhbmQgYSB0cmFjayByZWNvcmQgb2YgbGVhZGVyc2hpcCBhbmQgYWNjb21wbGlzaG1lbnRzLiBUaGUgaGlnaGVyIGNvbXBlbnNhdGlvbiByZWZsZWN0cyB0aGUgdmFsdWUgcGxhY2VkIG9uIHRoZSBleHBlcnRpc2UgYW5kIGNvbnRyaWJ1dGlvbnMgb2Ygc2VuaW9yIHByb2Zlc3Npb25hbHMgdG8gb3JnYW5pemF0aW9ucy4KCk92ZXJhbGwsIHNhbGFyaWVzIGluY3JlYXNlIHNpZ25pZmljYW50bHkgYXMgcHJvZmVzc2lvbmFscyBwcm9ncmVzcyBmcm9tIGVudHJ5IHRvIHNlbmlvciBsZXZlbHMsIHJlZmxlY3RpbmcgdGhlaXIgZXhwZXJpZW5jZSBhbmQgY29udHJpYnV0aW9ucyB0byBvcmdhbml6YXRpb25zLgoKIyMgVHJlZW1hcCBvZiBBdmVyYWdlIFNhbGFyeSBieSBFbXBsb3llZSBSZXNpZGVuY2UgYW5kIEpvYiBUaXRsZQoKYGBge3J9CiMgR2VvZ3JhcGhpY2FsIHNhbGFyeSBkaXN0cmlidXRpb24KIyBHcm91cCB0aGUgZGF0YQpncm91cGVkX2RhdGEgPC0gZmlsdGVyZWRfZGF0YSAlPiUKICBncm91cF9ieShlbXBsb3llZV9yZXNpZGVuY2UsIGpvYl90aXRsZSwgc2FsYXJ5X2luX3VzZCkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQoKIyBDYWxjdWxhdGUgYXZlcmFnZSBzYWxhcnkgcGVyIGdyb3VwCmF2ZXJhZ2Vfc2FsYXJ5IDwtIGdyb3VwZWRfZGF0YSAlPiUKICBncm91cF9ieShqb2JfdGl0bGUsIGVtcGxveWVlX3Jlc2lkZW5jZSkgJT4lCiAgc3VtbWFyaXNlKGF2Z19zYWxhcnkgPSBtZWFuKHNhbGFyeV9pbl91c2QpLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKIyBDcmVhdGUgdGhlIHRyZWVtYXAKZGF0YV9zY2llbmNlX3RyZWVtYXAgPC0gdHJlZW1hcChhdmVyYWdlX3NhbGFyeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBjKCJqb2JfdGl0bGUiLCAiZW1wbG95ZWVfcmVzaWRlbmNlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZTaXplID0gImF2Z19zYWxhcnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJUcmVlbWFwIG9mIEF2ZXJhZ2UgU2FsYXJ5IGJ5IEVtcGxveWVlIFJlc2lkZW5jZSBhbmQgSm9iIFRpdGxlIikKCiMgUHJpbnQgdGhlIHRyZWVtYXAKIyBwcmludChkYXRhX3NjaWVuY2VfdHJlZW1hcCkKZDN0cmVlKGRhdGFfc2NpZW5jZV90cmVlbWFwLCByb290bmFtZSA9ICJKb2JzIikKCmBgYApJbiB0aGlzIGFuYWx5c2lzLCB3ZSBnZW5lcmF0ZWQgYSB0cmVlbWFwIGdyYXBoIGFsb25nIHdpdGggaXRzIGludGVyYWN0aXZlIHZlcnNpb24sIHNob3djYXNpbmcgdGhlIGF2ZXJhZ2Ugc2FsYXJ5IGRpc3RyaWJ1dGlvbiBhY2NvcmRpbmcgdG8gZW1wbG95ZWUgcmVzaWRlbmNlIGFuZCBqb2IgdGl0bGVzLiBUaGUgdHJlZW1hcCB2aXN1YWxpemF0aW9uIGFsbG93ZWQgdXMgdG8gZXhwbG9yZSB0aGUgc2FsYXJ5IHRyZW5kcyBhY3Jvc3MgZGlmZmVyZW50IGNvdW50cmllcyBhbmQgam9iIHJvbGVzIGVmZmljaWVudGx5LgoKVXBvbiBleGFtaW5hdGlvbiBvZiB0aGUgZ3JhcGgsIGl0IHdhcyBldmlkZW50IHRoYXQgY2VydGFpbiBqb2IgdGl0bGVzIGNvbW1hbmRlZCBoaWdoZXIgYXZlcmFnZSBzYWxhcmllcyBhY3Jvc3MgdmFyaW91cyBjb3VudHJpZXMuIFNwZWNpZmljYWxseSwgcm9sZXMgc3VjaCBhcyBNTCBlbmdpbmVlciwgZGF0YSBlbmdpbmVlciwgZGF0YSBzY2llbnRpc3QsIGZpbmFuY2UgZGF0YSBhbmFseXN0LCBkYXRhIGFuYWx5c3QsIGFuZCBoZWFkIG9mIGRhdGEgY29uc2lzdGVudGx5IGVtZXJnZWQgd2l0aCB0aGUgaGlnaGVzdCBhdmVyYWdlIHNhbGFyaWVzLgoKIyMgU2FsYXJ5IFRyZW5kIGZvciBEYXRhIFNjaWVudGlzdHMgT3ZlciBXb3JrIFllYXJzCgpgYGB7cn0KIyBzYWxhcnkgb2Ygb3ZlciB5ZWFycwojIEZpbHRlciB0aGUgZGF0YSBmb3IgRGF0YSBTY2llbnRpc3RzCmRhdGFfc2NpZW50aXN0X3NhbGFyeSA8LSBmaWx0ZXJlZF9kYXRhW2ZpbHRlcmVkX2RhdGEkam9iX3RpdGxlID09ICJEYXRhIFNjaWVudGlzdCIsIF0KCiMgQ3JlYXRlIHRoZSBzY2F0dGVyIHBsb3QKc2NhdHRlcl9wbG90IDwtIGdncGxvdChkYXRhX3NjaWVudGlzdF9zYWxhcnksIGFlcyh4ID0gd29ya195ZWFyLCB5ID0gc2FsYXJ5X2luX3VzZCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiLCBhbHBoYSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiU2FsYXJ5IFRyZW5kIGZvciBEYXRhIFNjaWVudGlzdHMgT3ZlciBXb3JrIFllYXJzIiwKICAgICAgIHggPSAiV29yayBZZWFyIiwKICAgICAgIHkgPSAiU2FsYXJ5IChVU0QpIikKCiMgQWRkIHRyZW5kIGxpbmUKc2NhdHRlcl9wbG90X3dpdGhfdHJlbmQgPC0gc2NhdHRlcl9wbG90ICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJibGFjayIsIGxpbmV3aWR0aCA9IDAuNSkKCiMgQ29udmVydCB0byBwbG90bHkgb2JqZWN0CmludGVyYWN0aXZlX3Bsb3QgPC0gZ2dwbG90bHkoc2NhdHRlcl9wbG90X3dpdGhfdHJlbmQpCgojIFByaW50IHRoZSBpbnRlcmFjdGl2ZSBwbG90CmludGVyYWN0aXZlX3Bsb3QKCgojIFRPIENIRUNLIElGIFRIRSBUUkVORCBMSU5FIElTIElOQ1JFQVNJTkcvREVDUkVBU0lORwojIEZpdCBhIGxpbmVhciBtb2RlbCB0byB0aGUgZGF0YQpsbV9tb2RlbCA8LSBsbShzYWxhcnlfaW5fdXNkIH4gd29ya195ZWFyLCBkYXRhID0gZGF0YV9zY2llbnRpc3Rfc2FsYXJ5KQoKIyBHZXQgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgbGluZWFyIG1vZGVsIGFuZCBzbG9wCmNvZWZmaWNpZW50cyA8LSBjb2VmKGxtX21vZGVsKQpzbG9wZSA8LSBjb2VmZmljaWVudHNbMl0KCiMgQ2hlY2sgaWYgdGhlIHNsb3BlIGlzIHBvc2l0aXZlLCBpbmRpY2F0aW5nIGFuIGluY3JlYXNlIG92ZXIgeWVhcnMKaWYgKHNsb3BlID4gMCkgewogIGNhdCgiVGhlIHRyZW5kIGxpbmUgaW5kaWNhdGVzIGFuIGluY3JlYXNlIGluIHNhbGFyaWVzIG92ZXIgdGhlIHllYXJzLiIpCn0gZWxzZSBpZiAoc2xvcGUgPT0gMCkgewogIGNhdCgiVGhlIHRyZW5kIGxpbmUgaW5kaWNhdGVzIG5vIGNoYW5nZSBpbiBzYWxhcmllcyBvdmVyIHRoZSB5ZWFycy4iKQp9IGVsc2UgewogIGNhdCgiVGhlIHRyZW5kIGxpbmUgaW5kaWNhdGVzIGEgZGVjcmVhc2UgaW4gc2FsYXJpZXMgb3ZlciB0aGUgeWVhcnMuIikKfQoKYGBgCkJhc2VkIG9uIG91ciBhbmFseXNpcyBmb2N1c2luZyBvbiB0aGUgZGF0YSBzY2llbnRpc3Qgcm9sZSwgd2hpY2ggYXBwZWFycyB0byBoYXZlIHRoZSBoaWdoZXN0IHJlcHJlc2VudGF0aW9uIGFjcm9zcyB0aGUgc2VsZWN0ZWQgY291bnRyaWVzLCB3ZSBpbnZlc3RpZ2F0ZWQgdGhlIHNhbGFyeSB0cmVuZHMgb3ZlciB0aGUgeWVhcnMuIE91ciBleGFtaW5hdGlvbiwgYXMgZGVwaWN0ZWQgaW4gdGhlIGdyYXBoIGFuZCBjb25maXJtZWQgYnkgdGhlIGxpbmVhciBtb2RlbCByZXN1bHRzLCByZXZlYWxzIGEgc3VidGxlIGJ1dCBkaXNjZXJuaWJsZSBpbmNyZWFzZSBpbiBzYWxhcnkgb3ZlciB0aGUgeWVhcnMuIFdoaWxlIHRoZSB1cHdhcmQgdHJhamVjdG9yeSBpcyBldmlkZW50LCBpdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIHJhdGUgb2YgaW5jcmVhc2UgYXBwZWFycyB0byBiZSBtaW5pbWFsLiBUaGlzIG9ic2VydmF0aW9uIHN1Z2dlc3RzIHRoYXQgd2hpbGUgdGhlcmUgaXMgYSBwb3NpdGl2ZSB0cmVuZCBpbiBkYXRhIHNjaWVudGlzdCBzYWxhcmllcyBvdmVyIHRpbWUsIHRoZSBncm93dGggcmF0ZSBtYXkgYmUgcmVsYXRpdmVseSBzbG93LiBUaGlzIGluc2lnaHQgdW5kZXJzY29yZXMgdGhlIHN0YWJpbGl0eSBvciBtb2Rlc3QgZ3Jvd3RoIGluIGNvbXBlbnNhdGlvbiBmb3IgZGF0YSBzY2llbnRpc3RzIHdpdGhpbiB0aGUgc2VsZWN0ZWQgcmVnaW9ucyBvdmVyIHRoZSBzcGVjaWZpZWQgcGVyaW9kLiAKCgojIFJlc3VsdHMKCkluIHRoaXMgc3R1ZHksIHdlIGFuYWx5emVkIGRhdGEgZnJvbSAyNSByYW5kb21seSBzZWxlY3RlZCBjb3VudHJpZXMsIGZvY3VzaW5nIG9uIGZpdmUga2V5IHZhcmlhYmxlczogam9iIHRpdGxlLCBlbXBsb3llZSByZXNpZGVuY2UsIHNhbGFyeSBpbiBVU0QsIHdvcmsgZXhwZXJpZW5jZSwgYW5kIHdvcmsgeWVhci4gT3VyIGFuYWx5c2lzIGNvbXByaXNlZCBzZXZlcmFsIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbnMsIGVhY2ggb2ZmZXJpbmcgaW5zaWdodHMgaW50byBkaWZmZXJlbnQgYXNwZWN0cyBvZiB0aGUgZGF0YXNldDoKCgpDaGF0R1BUClJlc3VsdHMKCkluIHRoaXMgc3R1ZHksIHdlIGFuYWx5emVkIGRhdGEgZnJvbSAyNSByYW5kb21seSBzZWxlY3RlZCBjb3VudHJpZXMsIGZvY3VzaW5nIG9uIGZpdmUga2V5IHZhcmlhYmxlczogam9iIHRpdGxlLCBlbXBsb3llZSByZXNpZGVuY2UsIHNhbGFyeSBpbiBVU0QsIHdvcmsgZXhwZXJpZW5jZSwgYW5kIHdvcmsgeWVhci4gT3VyIGFuYWx5c2lzIGNvbXByaXNlZCBzZXZlcmFsIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbnMsIGVhY2ggb2ZmZXJpbmcgaW5zaWdodHMgaW50byBkaWZmZXJlbnQgYXNwZWN0cyBvZiB0aGUgZGF0YXNldDoKCi0gU2NhdHRlcnBsb3QgQW5hbHlzaXM6IFdlIGNvbmR1Y3RlZCBhIHNjYXR0ZXJwbG90IGFuYWx5c2lzIHRvIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZW1wbG95ZWUgcmVzaWRlbmNlIGFuZCBzYWxhcnkgaW4gVVNELgotIFN0YWNrZWQgQmFycGxvdDogQSBzdGFja2VkIGJhcnBsb3Qgd2FzIHV0aWxpemVkIHRvIGlsbHVzdHJhdGUgdGhlIHByZXZhbGVuY2Ugb2YgdmFyaW91cyBqb2IgdGl0bGVzIGFjcm9zcyBkaWZmZXJlbnQgZW1wbG95ZWUgcmVzaWRlbmNlIGNvdW50cmllcy4KLSBCYXJwbG90IG9mIEV4cGVyaWVuY2UgTGV2ZWxzOiBXZSBjcmVhdGVkIGEgYmFycGxvdCBkZXBpY3RpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBleHBlcmllbmNlIGxldmVscyBhbW9uZyB0aGUgc2FtcGxlZCBkYXRhLgotIEF2ZXJhZ2UgU2FsYXJ5IE92ZXIgWWVhcnM6IEEgbGluZXBsb3QgZ3JhcGggd2FzIGdlbmVyYXRlZCB0byBkaXNwbGF5IHRoZSBhdmVyYWdlIHNhbGFyeSB0cmVuZHMgb3ZlciB0aGUgeWVhcnMuCi0gU2FsYXJ5IERpc3RyaWJ1dGlvbiBieSBKb2IgVGl0bGU6IFdlIGVtcGxveWVkIGEgYm94cGxvdCB0byBzaG93Y2FzZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHNhbGFyaWVzIGFjY29yZGluZyB0byBkaWZmZXJlbnQgam9iIHRpdGxlcy4KLSBTYWxhcnkgRGlzdHJpYnV0aW9uIGJ5IEV4cGVyaWVuY2UgTGV2ZWw6IEFub3RoZXIgYm94cGxvdCB3YXMgdXRpbGl6ZWQgdG8gdmlzdWFsaXplIHRoZSBzYWxhcnkgZGlzdHJpYnV0aW9uIGFjcm9zcyB2YXJpb3VzIGV4cGVyaWVuY2UgbGV2ZWxzLgotIFRyZWVtYXAgVmlzdWFsaXphdGlvbjogQSB0cmVlbWFwIHdhcyBjb25zdHJ1Y3RlZCB0byBwcmVzZW50IHRoZSBhdmVyYWdlIHNhbGFyeSBkaXN0cmlidXRpb24gYnkgZW1wbG95ZWUgcmVzaWRlbmNlIGFuZCBqb2IgdGl0bGUuCi0gU2FsYXJ5IFRyZW5kIEFuYWx5c2lzIGZvciBEYXRhIFNjaWVudGlzdHM6IEZpbmFsbHksIHdlIGNvbmR1Y3RlZCBhIHRyZW5kIGFuYWx5c2lzIHNwZWNpZmljYWxseSBmb2N1c2luZyBvbiB0aGUgc2FsYXJ5IHRyZW5kIGZvciBkYXRhIHNjaWVudGlzdHMgb3ZlciB0aGUgeWVhcnMuCgpUaGVzZSBncmFwaGljYWwgcmVwcmVzZW50YXRpb25zIG9mZmVyIHZhbHVhYmxlIGluc2lnaHRzIGludG8gdGhlIGRhdGFzZXQsIHByb3ZpZGluZyBhIGNvbXByZWhlbnNpdmUgdW5kZXJzdGFuZGluZyBvZiBzYWxhcnkgZGlzdHJpYnV0aW9ucywgdHJlbmRzLCBhbmQgdmFyaWF0aW9ucyBhY3Jvc3MgZGlmZmVyZW50IHZhcmlhYmxlcyBhbmQgb3ZlciB0aW1lLgoKCiMgQ29uY2x1c2lvbnMKCkluIHRoaXMgY29tcHJlaGVuc2l2ZSBhbmFseXNpcywgd2UgZGVsdmVkIGludG8gdmFyaW91cyBhc3BlY3RzIG9mIHNhbGFyeSBkaXN0cmlidXRpb24sIHdvcmtmb3JjZSBjb21wb3NpdGlvbiwgYW5kIHNhbGFyeSB0cmVuZHMgYWNyb3NzIGRpZmZlcmVudCBqb2IgdGl0bGVzLCBleHBlcmllbmNlIGxldmVscywgYW5kIGdlb2dyYXBoaWNhbCByZWdpb25zLiBUaHJvdWdoIGludGVyYWN0aXZlIHZpc3VhbGl6YXRpb25zIGFuZCBzdGF0aXN0aWNhbCBhbmFseXNlcywgd2UgZ2FpbmVkIHZhbHVhYmxlIGluc2lnaHRzIGludG8gdGhlIGR5bmFtaWNzIG9mIGNvbXBlbnNhdGlvbiB3aXRoaW4gdGhlIGluZHVzdHJ5LgoKVGhlIHNjYXR0ZXJwbG90IGRlcGljdGluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc2FsYXJ5IGFuZCBlbXBsb3llZSByZXNpZGVuY2UgcmV2ZWFsZWQgc2lnbmlmaWNhbnQgdmFyaWF0aW9ucyBpbiBzYWxhcnkgbGV2ZWxzIGFjcm9zcyBkaWZmZXJlbnQgY291bnRyaWVzLCB1bmRlcnNjb3JpbmcgcmVnaW9uYWwgZGlzcGFyaXRpZXMgYW5kIHBvdGVudGlhbCBmYWN0b3JzIGluZmx1ZW5jaW5nIGNvbXBlbnNhdGlvbi4gRnVydGhlcm1vcmUsIHRoZSBzdGFja2VkIGJhcnBsb3QgcHJvdmlkZWQgYSBjbGVhciBvdmVydmlldyBvZiB0aGUgcHJldmFsZW5jZSBvZiBkaWZmZXJlbnQgam9iIHRpdGxlcyBhY3Jvc3MgdmFyaW91cyBlbXBsb3llZSByZXNpZGVuY2VzLCBoaWdobGlnaHRpbmcgY291bnRyaWVzIHdpdGggYSBoaWdoIGNvbmNlbnRyYXRpb24gb2Ygc3BlY2lmaWMgcm9sZXMuCgpFeGFtaW5pbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBleHBlcmllbmNlIGxldmVscyBhbW9uZyBlbXBsb3llZXMgb2ZmZXJlZCBpbnNpZ2h0cyBpbnRvIHRoZSB3b3JrZm9yY2UgY29tcG9zaXRpb24sIHdpdGggYSBub3RhYmxlIHByZXNlbmNlIG9mIG1pZC1sZXZlbCBhbmQgc2VuaW9yLWxldmVsIHBvc2l0aW9ucy4gVGhpcyBkaXN0cmlidXRpb24gcmVmbGVjdHMgdGhlIG1hdHVyaXR5IGFuZCBleHBlcnRpc2Ugb2YgdGhlIHdvcmtmb3JjZSwgZXNzZW50aWFsIGZvciB1bmRlcnN0YW5kaW5nIHRhbGVudCBkZW1vZ3JhcGhpY3MgYW5kIHBsYW5uaW5nIG9yZ2FuaXphdGlvbmFsIHN0cmF0ZWdpZXMuCgpUaGUgYW5hbHlzaXMgb2YgYXZlcmFnZSBzYWxhcnkgdHJlbmRzIG92ZXIgdGhlIHllYXJzIHVudmVpbGVkIGEgcG9zaXRpdmUgdHJhamVjdG9yeSwgd2l0aCBzYWxhcmllcyBleHBlcmllbmNpbmcgYSBzdGVhZHkgaW5jcmVhc2Ugb3ZlciB0aW1lLiBUaGlzIGdyb3d0aCByZWZsZWN0cyBicm9hZGVyIGVjb25vbWljIGNvbmRpdGlvbnMsIGluZHVzdHJ5IGRlbWFuZCwgYW5kIGV2b2x2aW5nIHNraWxsIHJlcXVpcmVtZW50cyBjb250cmlidXRpbmcgdG8gc2FsYXJ5IGVzY2FsYXRpb25zIGFjcm9zcyBkaWZmZXJlbnQgam9iIHJvbGVzIGFuZCByZWdpb25zLgoKVGhlIGV4YW1pbmF0aW9uIG9mIHNhbGFyeSBkaXN0cmlidXRpb25zIGJ5IGpvYiB0aXRsZSBhbmQgZXhwZXJpZW5jZSBsZXZlbCBwcm92aWRlZCBhIG51YW5jZWQgdW5kZXJzdGFuZGluZyBvZiBjb21wZW5zYXRpb24gc3RydWN0dXJlcyB3aXRoaW4gdGhlIGluZHVzdHJ5LiBSb2xlcyBzdWNoIGFzIEhlYWQgb2YgRGF0YSwgUmVzZWFyY2ggRW5naW5lZXIsIGFuZCBBSSBEZXZlbG9wZXIgZW1lcmdlZCB3aXRoIG5vdGFibGUgc2FsYXJ5IHZhcmlhdGlvbnMsIGluZGljYXRpdmUgb2YgdGhlIGRpdmVyc2Ugc2tpbGxzZXRzIGFuZCByZXNwb25zaWJpbGl0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGVzZSBwb3NpdGlvbnMuIEFkZGl0aW9uYWxseSwgdGhlIGFuYWx5c2lzIGhpZ2hsaWdodGVkIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIHNhbGFyaWVzIGFjcm9zcyBleHBlcmllbmNlIGxldmVscywgZW1waGFzaXppbmcgdGhlIGltcG9ydGFuY2Ugb2YgZXhwZXJ0aXNlIGFuZCBzZW5pb3JpdHkgaW4gZHJpdmluZyBjb21wZW5zYXRpb24gbGV2ZWxzLgoKRmluYWxseSwgdGhlIHRyZWVtYXAgdmlzdWFsaXphdGlvbiBvZmZlcmVkIGEgY29tcHJlaGVuc2l2ZSB2aWV3IG9mIGF2ZXJhZ2Ugc2FsYXJ5IGRpc3RyaWJ1dGlvbnMgYWNyb3NzIGVtcGxveWVlIHJlc2lkZW5jZXMgYW5kIGpvYiB0aXRsZXMsIGhpZ2hsaWdodGluZyBsdWNyYXRpdmUgcm9sZXMgYW5kIHJlZ2lvbnMgd2l0aGluIHRoZSBpbmR1c3RyeS4gQnkgZm9jdXNpbmcgb24gdGhlIGRhdGEgc2NpZW50aXN0IHJvbGUsIHdlIG9ic2VydmVkIGEgc3VidGxlIHlldCBkaXNjZXJuaWJsZSBpbmNyZWFzZSBpbiBzYWxhcnkgb3ZlciB0aGUgeWVhcnMsIGluZGljYXRpbmcgc3RhYmxlIG9yIG1vZGVzdCBncm93dGggaW4gY29tcGVuc2F0aW9uIGZvciBwcm9mZXNzaW9uYWxzIHdpdGhpbiB0aGlzIGRvbWFpbi4KCkluIGNvbmNsdXNpb24sIHRoaXMgYW5hbHlzaXMgcHJvdmlkZXMgdmFsdWFibGUgaW5zaWdodHMgZm9yIGluZHVzdHJ5IHN0YWtlaG9sZGVycywgcG9saWN5bWFrZXJzLCBhbmQgcHJvZmVzc2lvbmFscyBzZWVraW5nIHRvIHVuZGVyc3RhbmQgc2FsYXJ5IGR5bmFtaWNzLCB3b3JrZm9yY2UgdHJlbmRzLCBhbmQgcmVnaW9uYWwgdmFyaWF0aW9ucyB3aXRoaW4gdGhlIGZpZWxkLiBCeSBsZXZlcmFnaW5nIGludGVyYWN0aXZlIHZpc3VhbGl6YXRpb25zIGFuZCBzdGF0aXN0aWNhbCBhbmFseXNlcywgd2UgaGF2ZSBzaGVkIGxpZ2h0IG9uIGtleSBmYWN0b3JzIHNoYXBpbmcgY29tcGVuc2F0aW9uIHRyZW5kcywgb2ZmZXJpbmcgYSByb2J1c3QgZm91bmRhdGlvbiBmb3IgaW5mb3JtZWQgZGVjaXNpb24tbWFraW5nIGFuZCBzdHJhdGVnaWMgcGxhbm5pbmcgaW4gdGhlIGV2ZXItZXZvbHZpbmcgbGFuZHNjYXBlIG9mIHRoZSBpbmR1c3RyeS4KCgoKCgo=